// GFX/Frame.cpp
#include <core/std.h>
#include "Frame.h"

using namespace GFX;

int Frame::AttachFrame(Frame * pChild)
{
	int iFrame = ARRAY_NOT_FOUND;

	pChild->m_pParent = this;
	pChild->m_bValid = false;

	iFrame = m_pChildren.Find(pChild);

	if (iFrame == ARRAY_NOT_FOUND) {
		iFrame = m_pChildren.Append(pChild);
		pChild->Invalidate();
	}

	return iFrame;
}

void Frame::DetachFrame(Frame * pChild)
{
	pChild->m_pParent = 0;
	pChild->Invalidate();

	int iIndex = m_pChildren.Find(pChild);

	m_pChildren.Remove(iIndex);
}

int Frame::FindChild(Frame * pChild)
{
	return m_pChildren.Find(pChild);
}

void Frame::Clear()
{
	DetachAll();

	m_Local.Identity();
	m_World.Identity();
	m_bValid = false;
}

void Frame::Invalidate()
{
	m_bValid = false;

	for (int iChild = 0; iChild < m_pChildren.GetSize(); ++iChild)
		m_pChildren[iChild]->Invalidate();
}

const Math::mat4 & Frame::Evaluate() const
{
	if (!m_bValid)
	{
		if (m_pParent) {
			const Math::mat4 & matParent = m_pParent->Evaluate();
			m_World = m_Local * matParent;
		}
		else
			m_World = m_Local;

		m_bValid = true;
	}

	return m_World;
}

void Frame::DetachAll()
{
	Frame * pParent = m_pParent;

	if (m_pParent)
		m_pParent->DetachFrame(this);

	// re-attach frames
	for (int iChild = 0; iChild < m_pChildren.GetSize(); ++iChild)
	{
		if (pParent)
			pParent->AttachFrame(m_pChildren[iChild]);
		else
		{
			m_pChildren[iChild]->m_pParent = 0;
			m_pChildren[iChild]->Invalidate();
		}
	}

	m_pChildren.SetSize(0);
}